/**
 * Copyright (C) 2005-2011 by Insider Guides, LLC                       
 * info@framewerk.org                                                   
 *                                                                      
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the      
 * "Software"), to deal in the Software without restriction, including  
 * without limitation the rights to use, copy, modify, merge, publish,  
 * distribute, sublicense, and#or sell copies of the Software, and to   
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:                                            
 *                                                                      
 * The above copyright notice and this permission notice shall be       
 * included in all copies or substantial portions of the Software.      
 *                                                                      
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,      
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF   
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR    
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.                                      
 */
//Marks the right margin of code *******************************************************************
package com.rmc.utils
{
  
  //--------------------------------------
  //  Imports
  //--------------------------------------
  import com.greensock.TweenMax;
  import com.greensock.data.TweenMaxVars;
  
  import flash.display.DisplayObject;
  import flash.display.DisplayObjectContainer;
  import flash.display.Sprite;
  import flash.utils.Timer;
  import flash.utils.getDefinitionByName;
  import flash.utils.getQualifiedClassName;
  import flash.utils.getQualifiedSuperclassName;
  import flash.utils.setInterval;
  
  
  //--------------------------------------
  //  Metadata
  //--------------------------------------
  
  //--------------------------------------
  //  Class
  //--------------------------------------
  /**
   * <p>The <code>AS3Utility</code> class has many helpful class-level and object-level helper methods.</p>
   * 
   * <p>AUTHOR 		: Samuel Asher Rivello</p>
   * <p>COMPANY 		: Rivello Multimedia Consulting</p>
   * <p>CREATION DATE 	: Nov 9, 2010</p>
   *  
   * @example Here is a code example. 
   *  
   * <listing version="3.0">
   * <p>Describe this code example.</p>
   *
   * </listing>
   *
   */
  public class AS3Utility
  {		
    
    //--------------------------------------
    //  Properties
    //--------------------------------------
    //PUBLIC GETTER/SETTERS
    
    //PUBLIC CONST
    
    //PRIVATE
    
    //PRIVATE CONST
    /**
     * Holds the return expected when calling typeOf (new Function()), this is used to check if a object has a method. Tricky, but works perfect.
     * 
     * 
     */
    private static const _FUNCTION_TYPE_AS_STRING : String ="function Function() {}";
    
    
    //--------------------------------------
    //  Constructor
    //--------------------------------------
    
    //--------------------------------------
    //  Methods
    //--------------------------------------		
    //PUBLIC	
    
    //PUBLIC STATIC
    /**
     * Merge 1+ <code>Vector</code>s into new <code>Vector</code>
     * 
     * @param rest <code>Rest</code> object containing 1 or more <code>Vector</code> to merge.
     * 
     * @return The <code>Vector</code> that is returned with all input <code>Vector</code>s merged.
     * 
     */
    public static function mergeClassVectors(...rest) : Vector.<Class>
    {
      var new_vector_class : Vector.<Class>= new Vector.<Class>();
      if (rest && rest.length) {
        for each (var vector_class : Vector.<Class> in rest) {
          for each (var item : * in vector_class) {
            new_vector_class.push( item);
          }
        }
      }
      
      return new_vector_class;
      
    }
    
    
    /**
     * Merge 1+ <code>Array</code>s into new <code>Array</code>.
     * 
     * @param rest <code>Rest</code> object containing 1 or more <code>Array</code>s to merge.
     * 
     * @return The <code>Array</code> that is returned with all input <code>Array</code>s merged.
     * 
     */
    public static function mergeArrays(...rest) : Array 
    {
      var new_array : Array = new Array();
      if (rest && rest.length) {
        for each (var array : Array in rest) {
          for each (var item : * in array) {
            new_array.push( item);
          }
        }
      }
      
      return new_array;
      
    }
    
    /**
     * Return the path+className for the class of which the object instance belongs.
     * 
     * @param object The Object to Introspect
     * 
     * @return String of the name in the format "package.ClassName"
     * 
     */		
    public static function getFullyQualifiedPathAndClassNameForObject(object : Object ) : String
    {
      var qualifiedClassName_str : String = getQualifiedClassName( object );
      return qualifiedClassName_str.replace("::",".");
    } 
    
    /**
     * Return the path+className for the class of which the object instance belongs.
     * 
     * @param object The Object to Introspect
     * 
     * @return String of the name in the format "package.ClassName"
     * 
     */		
    public static function getFullyQualifiedPathAndClassNameForClass(the_class : Class ) : String
    {
      return getFullyQualifiedPathAndClassNameForObject(the_class);
    } 
    
    /**
     * Return the Class for which the Object Instance belongs.
     * 
     * @param object The Object to Introspect
     * 
     * @return Class
     * 
     */		
    public static function getClassTypeFromInstance(object : Object ) : Class
    {
      
      var qualifiedClassName_str : String = getQualifiedClassName( object );
      var clazz : Class =  getDefinitionByName( qualifiedClassName_str ) as Class;
      
      if (clazz != null ) {
        return clazz;
      } else {
        //THIS SHOULD NEVER HAPPEN
        throw new Error ("AS3Utility.getClassTypeFromInstance() cannot find Class for Instance " + object);
        return null;
      }
    } 
    
    /**
     * Return the Super Class for which the Object Instance belongs.
     * 
     * @param object The Object to Introspect
     * 
     * @return Class
     * 
     */		
    public static function getSuperClassTypeFromInstance(object : Object ) : Class
    {
      
      // NOT TESTED YET - SRIVELLO (REMOVE COMMENT IF IT WORKS)
      var qualifiedClassName_str: String = getQualifiedSuperclassName(object);
      if (qualifiedClassName_str == null) {
        return(null);
      } else {
        return	getDefinitionByName(qualifiedClassName_str) as Class;	
        
      }
      
    } 
    /**
     * Determines if a class (static method) or instance (instance method) contains the requested method
     * 
     * NOTE: This is like 'hasOwnProperty', but it also works with static methods.
     * 
     * @param object The Object to introspect
     * @param aMethod_str The method string to look for
     * 
     * @return Boolean
     * 
     */		
    public static function getObjectOrClassHasThisMethod(object : Object, aMethod_str : String) : Boolean
    {
      //attempts to 'look up' the method string using [ ] notation and see if that matches the expected (i.e. that method exists).
      var return_object : Object = object[aMethod_str];
      var return_object_str : String = return_object.toString();
      return return_object_str == AS3Utility._FUNCTION_TYPE_AS_STRING;
    } 
    
    /**
     * @copy com.myyearbook.utils.GraphicsHelper#clearAllGraphicsFromSprite
     * 
     */		
    public static function clearAllGraphicsFromSprite(parentToClear_sprite : Sprite ) : void
    {
      GraphicsHelper.clearAllGraphics(parentToClear_sprite.graphics);
    } 
    
    /**
     * @copy com.myyearbook.utils.DisplayObjectHelper#removeAllDisplayListChildrenFromParent
     * 
     */	
    public static function removeAllDisplayListChildrenFromParent(parentToClear_sprite : Sprite ) : void
    {
      DisplayObjectHelper.removeAllDisplayListChildrenFromParent(parentToClear_sprite);
    } 
    
    /**
     * @copy com.myyearbook.utils.DisplayObjectHelper#removeDisplayListChildFromParent
     * 
     */		
    public static function removeDisplayListChildFromParent(child_displayobject : DisplayObject, parent_displayobjectcontainer : DisplayObjectContainer ) : void
    {
      DisplayObjectHelper.removeDisplayListChildFromParent(child_displayobject, parent_displayobjectcontainer);
      
    } 
    
    /**
     * Set target[property] = value, if value exists. This saves if-then statements spread through codebase.
     * 
     * @param targetObject The <code>Object</code> to be copied to.
     * @param targetPropertyName_str The <code>String</code> property name.
     * @param sourcePropertyObject The <code>Object</code> value to be copied from.
     * 
     * @return void
     * 
     */		
    public static function setValueBasedOnOptionalVariable(targetObject : Object , targetPropertyName_str : String, sourcePropertyObject : Object ) : void		
    {
      if (sourcePropertyObject != null && targetObject) {
        targetObject[targetPropertyName_str] = sourcePropertyObject;
        //Debugger.debug( "setValueBasedOnOptionalVariable: name : '" + targetPropertyName_str + "' has value '" + targetObject[targetPropertyName_str] + "'.");
      }
    }  
    
    /**
     * Call a function. Repeatedly if desired, on delay if desired. Nice.
     * 
     * @param closureFunction : Function 
     * @param delay_uint : uint = 0. In milliseconds.
     * @param repeat_uint : uint = 0. Where 0 means execute 1 time.
     * @param parameters_array : Array = null 
     * 
     * @return void
     * 
     */		
    public static function callFunction (closureFunction : Function , delay_uint : uint = 0, timesToCall_uint : uint = 1, parameters_array : Array = null ) : void		
    {
      if (timesToCall_uint < 1) {
        throw new Error ("CallFunction's parameter 'timesToCall_uint' must be >= 1");
      }
      var tweenMaxVars : TweenMaxVars = new TweenMaxVars ();
      tweenMaxVars.repeat (timesToCall_uint - 1);
      tweenMaxVars.onRepeat(closureFunction, parameters_array);
      tweenMaxVars.onComplete(closureFunction, parameters_array);
      TweenMax.to (AS3Utility, delay_uint/1000, tweenMaxVars);
    }  
    
    
    //PRIVATE	
    
    
    //--------------------------------------
    //  Event Handlers
    //--------------------------------------		
    
  }
}